package com.bauer.module.common.utils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * @Author ：rui.wei
 * @Date ：Created in 16:44 2019/9/11
 * @Description：
 */
public class AESEncryptUtils {

    /**
     * AES加解密
     */
    private static final String ALGORITHM = "AES";
    /**
     * 默认的初始化向量值
     */
    private static final String IV_DEFAULT = "g8v20drvOmIx2PuR";
    /**
     * 默认加密的KEY
     */
    private static final String KEY_DEFAULT = "8G5M4Ff9hel8fUA9";
    /**
     * 工作模式：CBC
     */
    private static final String TRANSFORM_CBC_PKCS5 = "AES/CBC/PKCS5Padding";

    /**
     * 工作模式：ECB
     */
    private static final String TRANSFORM_ECB_PKCS5 = "AES/ECB/PKCS5Padding";

    /**
     * 基于CBC工作模式的AES加密
     *
     * @param value 待加密字符串
     * @param key 秘钥，如果不填则使用默认值
     * @param iv 初始化向量值，如果不填则使用默认值
     * @return java.lang.String
     */
    public static String encryptCbcMode(final String value, String key, String iv) {
        if (value == null) {
            return null;
        }
        if (iv == null || iv.length() != 16) {
            iv = IV_DEFAULT;
        }

        final SecretKeySpec keySpec = getSecretKey(key);

        final IvParameterSpec ivParameterSpec = new IvParameterSpec(getUTF8Bytes(iv));

        try {
            Cipher encipher = Cipher.getInstance(TRANSFORM_CBC_PKCS5);

            //加密模式
            encipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec);
            //使用AES加密
            byte[] encrypted = encipher.doFinal(getUTF8Bytes(value));
            //然后转成BASE64返回
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 基于CBC工作模式的AES解密
     *
     * @param encryptedStr AES加密之后的字符串
     * @param key 秘钥，如果不填则使用默认值
     * @param iv 初始化向量值，如果不填则使用默认值
     * @return java.lang.String
     * @author zifangsky
     * @date 2018/8/14 11:42
     * @since 1.0.0
     */
    public static String decryptCbcMode(final String encryptedStr, String key, String iv) {
        if (encryptedStr == null) {
            return null;
        }
        //iv为空，则使用默认值
        if (iv == null || iv.length() != 16) {
            iv = IV_DEFAULT;
        }

        final SecretKeySpec keySpec = getSecretKey(key);
        final IvParameterSpec ivParameterSpec = new IvParameterSpec(getUTF8Bytes(iv));

        try {
            Cipher encipher = Cipher.getInstance(TRANSFORM_CBC_PKCS5);

            //加密模式
            encipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);
            //先用BASE64解密
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedStr);
            //然后再AES解密
            byte[] originalBytes = encipher.doFinal(encryptedBytes);
            //返回字符串
            return new String(originalBytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 基于ECB工作模式的AES加密
     *
     * @param value 待加密字符串
     * @param key 秘钥，如果不填则使用默认值
     * @return java.lang.String
     */
    public static String encryptEcbMode(final String value, String key) {
        if (value == null) {
            return null;
        }
        //如果key为空，则使用默认值
        if (key == null || key.length() != 16) {
            key = KEY_DEFAULT;
        }

        //密码
        final SecretKeySpec keySpec = getSecretKey(key);

        try {
            Cipher encipher = Cipher.getInstance(TRANSFORM_ECB_PKCS5);

            //加密模式
            encipher.init(Cipher.ENCRYPT_MODE, keySpec);
            //使用AES加密
            byte[] encrypted = encipher.doFinal(getUTF8Bytes(value));
            //然后转成BASE64返回
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 基于ECB工作模式的AES解密
     *
     * @param encryptedStr AES加密之后的字符串
     * @param key 秘钥，如果不填则使用默认值
     * @return java.lang.String
     */
    public static String decryptEcbMode(final String encryptedStr, String key) {
        if (encryptedStr == null) {
            return null;
        }
        //如果key为空，则使用默认值
        if (key == null || key.length() != 16) {
            key = KEY_DEFAULT;
        }

        //密码
        final SecretKeySpec keySpec = getSecretKey(key);

        try {
            Cipher encipher = Cipher.getInstance(TRANSFORM_ECB_PKCS5);

            //加密模式
            encipher.init(Cipher.DECRYPT_MODE, keySpec);
            //先用BASE64解密
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedStr);
            //然后再AES解密
            byte[] originalBytes = encipher.doFinal(encryptedBytes);
            //返回字符串
            return new String(originalBytes);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 将字符串转化为UTF8格式的byte数组
     *
     * @param input the input string
     * @return UTF8 bytes
     */
    private static byte[] getUTF8Bytes(String input) {
        return input.getBytes(StandardCharsets.UTF_8);
    }

    /**
     * 生成加密秘钥
     *
     * @param KEY 明文秘钥
     * @return SecretKeySpec
     */
    private static SecretKeySpec getSecretKey(final String KEY) {
        //生成指定算法密钥
        KeyGenerator generator = null;

        try {
            generator = KeyGenerator.getInstance(ALGORITHM);

            //指定AES密钥长度（128、192、256）
            generator.init(256, new SecureRandom(getUTF8Bytes(KEY)));

            //生成一个密钥
            SecretKey secretKey = generator.generateKey();
            //转换为AES专用密钥
            return new SecretKeySpec(secretKey.getEncoded(), ALGORITHM);
        } catch (NoSuchAlgorithmException ex) {
            ex.printStackTrace();
        }

        return null;
    }

    public static void main(String[] args) {
        String key = "Ct7TyXZa19rgQKK";
        String content = "{\"username\":\"Tom\",\"password\":\"123456\",\"mobile\":\"12306\",\"email\":\"admin@zifangsky.cn\"}";
        String encryptedStr = encryptCbcMode(content, key, null);
        System.out.println(encryptedStr);

        String originalStr2 = decryptCbcMode(encryptedStr, key, null);
        System.out.println(originalStr2);

    }

}